#pragma once

/************************
*          GUI          *
************************/

struct tcl_reg_vars {
	const char* const sig;
	const char* const unsig;
	const char* const hex;
	const char* const bytes[8][8];
};

static const struct tcl_reg_vars tclRegVars[] = {
	{
		.sig   = "reg0s",
		.unsig = "reg0u",
		.hex   = "reg0h",
		.bytes = {
			{ "reg0b00", "reg0b01", "reg0b02", "reg0b03", "reg0b04", "reg0b05", "reg0b06", "reg0b07",  },
			{ "reg0b10", "reg0b11", "reg0b12", "reg0b13", "reg0b14", "reg0b15", "reg0b16", "reg0b17",  },
			{ "reg0b20", "reg0b21", "reg0b22", "reg0b23", "reg0b24", "reg0b25", "reg0b26", "reg0b27",  },
			{ "reg0b30", "reg0b31", "reg0b32", "reg0b33", "reg0b34", "reg0b35", "reg0b36", "reg0b37",  },
			{ "reg0b40", "reg0b41", "reg0b42", "reg0b43", "reg0b44", "reg0b45", "reg0b46", "reg0b47",  },
			{ "reg0b50", "reg0b51", "reg0b52", "reg0b53", "reg0b54", "reg0b55", "reg0b56", "reg0b57",  },
			{ "reg0b60", "reg0b61", "reg0b62", "reg0b63", "reg0b64", "reg0b65", "reg0b66", "reg0b67",  },
			{ "reg0b70", "reg0b71", "reg0b72", "reg0b73", "reg0b74", "reg0b75", "reg0b76", "reg0b77",  },
		},
	},
	{
		.sig   = "reg1s",
		.unsig = "reg1u",
		.hex   = "reg1h",
		.bytes = {
			{ "reg1b00", "reg1b01", "reg1b02", "reg1b03", "reg1b04", "reg1b05", "reg1b06", "reg1b07",  },
			{ "reg1b10", "reg1b11", "reg1b12", "reg1b13", "reg1b14", "reg1b15", "reg1b16", "reg1b17",  },
			{ "reg1b20", "reg1b21", "reg1b22", "reg1b23", "reg1b24", "reg1b25", "reg1b26", "reg1b27",  },
			{ "reg1b30", "reg1b31", "reg1b32", "reg1b33", "reg1b34", "reg1b35", "reg1b36", "reg1b37",  },
			{ "reg1b40", "reg1b41", "reg1b42", "reg1b43", "reg1b44", "reg1b45", "reg1b46", "reg1b47",  },
			{ "reg1b50", "reg1b51", "reg1b52", "reg1b53", "reg1b54", "reg1b55", "reg1b56", "reg1b57",  },
			{ "reg1b60", "reg1b61", "reg1b62", "reg1b63", "reg1b64", "reg1b65", "reg1b66", "reg1b67",  },
			{ "reg1b70", "reg1b71", "reg1b72", "reg1b73", "reg1b74", "reg1b75", "reg1b76", "reg1b77",  },
		},
	},
	{
		.sig   = "reg2s",
		.unsig = "reg2u",
		.hex   = "reg2h",
		.bytes = {
			{ "reg2b00", "reg2b01", "reg2b02", "reg2b03", "reg2b04", "reg2b05", "reg2b06", "reg2b07",  },
			{ "reg2b10", "reg2b11", "reg2b12", "reg2b13", "reg2b14", "reg2b15", "reg2b16", "reg2b17",  },
			{ "reg2b20", "reg2b21", "reg2b22", "reg2b23", "reg2b24", "reg2b25", "reg2b26", "reg2b27",  },
			{ "reg2b30", "reg2b31", "reg2b32", "reg2b33", "reg2b34", "reg2b35", "reg2b36", "reg2b37",  },
			{ "reg2b40", "reg2b41", "reg2b42", "reg2b43", "reg2b44", "reg2b45", "reg2b46", "reg2b47",  },
			{ "reg2b50", "reg2b51", "reg2b52", "reg2b53", "reg2b54", "reg2b55", "reg2b56", "reg2b57",  },
			{ "reg2b60", "reg2b61", "reg2b62", "reg2b63", "reg2b64", "reg2b65", "reg2b66", "reg2b67",  },
			{ "reg2b70", "reg2b71", "reg2b72", "reg2b73", "reg2b74", "reg2b75", "reg2b76", "reg2b77",  },
		},
	},
};

/******************************
*          FUNCTIONS          *
******************************/

struct tcl_callbacks {
	const char* tclFunc;
	int (*cFunc)( ClientData, Tcl_Interp*, int, Tcl_Obj* const[] );
};

//reg edit
static int regRstCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );
static int editRegCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );
static int editRegByteCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );
static int setOutputRegCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );
static int setRegSizeCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );

//math
static int opAddCore(  ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );
static int opSubCore(  ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );
static int opMulCore(  ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );
static int opImulCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );
static int opDivCore(  ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );
static int opIdivCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );
static int opNegCore(  ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );

//logic
static int opAndCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );
static int opNotCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );
static int opOrCore(  ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );
static int opXorCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );

//shift
static int opShlCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );
static int opShrCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );
static int opSalCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );
static int opSarCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );
static int opRolCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );
static int opRorCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );

//other
static int opBswapCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );
static int opMovsxCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] );

static const struct tcl_callbacks tclCallbacks[] = {
	
	//reg edit
	{ "regRst",       regRstCore       },
	{ "editReg",      editRegCore      },
	{ "editRegByte",  editRegByteCore  },
	{ "setOutputReg", setOutputRegCore },
	{ "setRegSize",   setRegSizeCore   },
	
	//math
	{ "opAdd",  opAddCore  },
	{ "opSub",  opSubCore  },
	{ "opMul",  opMulCore  },
	{ "opImul", opImulCore },
	{ "opDiv",  opDivCore  },
	{ "opIdiv", opIdivCore },
	{ "opNeg",  opNegCore  },
	
	//logic
	{ "opAnd", opAndCore },
	{ "opNot", opNotCore },
	{ "opOr",  opOrCore  },
	{ "opXor", opXorCore },
	
	//shift
	{ "opShl", opShlCore },
	{ "opShr", opShrCore },
	{ "opSal", opSalCore },
	{ "opSar", opSarCore },
	{ "opRol", opRolCore },
	{ "opRor", opRorCore },
	
	//other
	{ "opBswap", opBswapCore },
	{ "opMovsx", opMovsxCore },
	
	//list terminator
	{ NULL, NULL },
};
